#include "server.h"
int main() {
//	char* wel = "Server is running in background, wait your client now !\n";
//	fwrite(wel,sizeof(char),strlen(wel),stdout);
	be_daemon();

	int sfp_cmd;
	struct sockaddr_in s_add_cmd, c_add_cmd;
	int sin_size;
	printf("Hello,welcome to my server !\n");
	sfp_cmd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sfp_cmd) {
		printf("socket fail ! \n");
		return -1;
	}
	printf("socket ok !\r\n");

	memset(&s_add_cmd,0, sizeof(struct sockaddr_in));
	s_add_cmd.sin_family = AF_INET;
	s_add_cmd.sin_addr.s_addr = htonl(INADDR_ANY);
	s_add_cmd.sin_port = htons(PORTNUM_CMD);
	if (-1
			== bind(sfp_cmd, (struct sockaddr *) (&s_add_cmd),
					sizeof(struct sockaddr))) {
		printf("bind cmd fail !\n");
		exit(0);
	}

	printf("bind ok !\n");

	if (-1 == listen(sfp_cmd, 5)) {
		printf("listen fail !\n");
		return -1;
	}
	printf("listen ok\n");
	int k = 0;
	while (k != 1) { //进入死循环
		sin_size = sizeof(struct sockaddr_in);
		cfp_cmd = accept(sfp_cmd, (struct sockaddr*) (&c_add_cmd), &sin_size); //与客户端的命令通道连接
		printf("cfp_cmd accept ok\n");
		if (-1 == cfp_cmd) {
			printf("accept fail !\r\n");
			return -1;
		}
//		client_ip = (char*)malloc(15*sizeof(char));
		client_ip = inet_ntoa(c_add_cmd.sin_addr);
		printf("accept ok!\nServer start get connect from %#x : %#x\n",
				ntohl(c_add_cmd.sin_addr.s_addr), ntohs(c_add_cmd.sin_port));
		printf("client ip:%s\n",client_ip);
		pid_t fpid = fork();
		if (fpid == 0) {
			//子进程
			com_client(); //处理客户端链接
		} else if (fpid < 0) {
			printf("server fork error!");
			return -1;
		}
	}
	printf("no while\n");
	close(sfp_cmd);
	return 0;
}

void be_daemon(){
	time_t now;
	  int childpid,fd,fdtablesize;
	  int error,in,out;
	  /* 忽略终端 I/O信号,STOP信号 */
	  signal(SIGTTOU,SIG_IGN);
	  signal(SIGTTIN,SIG_IGN);
	  signal(SIGTSTP,SIG_IGN); 
	  signal(SIGHUP ,SIG_IGN);
	  /* 父进程退出,程序进入后台运行 */
	  if(fork()!=0) 
		  _exit(1);
	  if(setsid()<0)
		 _exit(1);/* 创建一个新的会议组 */ 
	   /* 子进程退出,孙进程没有控制终端了 */  
	  if(fork()!=0) 
		 _exit(1);
	 /*if(chdir("/tmp")==-1)
		 _exit(1);
	 /* 关闭打开的文件描述符,包括标准输入、标准输出和标准错误输出 */ 
	 for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++) 
	     close(fd);
	//与chmod正好相反 
	 umask(0);/*重设文件创建掩模 */ 
	 signal(SIGCHLD,SIG_IGN);/* 忽略SIGCHLD信号 */ 
		/*打开log系统*/
	 syslog(LOG_USER|LOG_INFO,"server start as a daemon process\n");  
}
void com_client() { 
	while (1) {
		char cmd[4]; //命令3字母，加上'\0'
		int length = recv(cfp_cmd, cmd, 3, MSG_WAITALL);
		if (3 == length) {
			cmd[3] = '\0';
#ifdef TEST
			printf("client command:%s\n", cmd);
#endif
			if (strcmp(cmd, DIR) == 0)
				cmd_dir();
			else if (strcmp(cmd, BYE) == 0)
				cmd_bye();
			else if (strcmp(cmd, GET) == 0) { //如果是get命令，还需要读入后面的文件名
				char buf[128];
				length = read(cfp_cmd, buf, 128);
				buf[length] = '\0';
				char* filename = buf + 1; //去掉首位的空格
				printf("require file:%s\n", filename);
				cmd_get(filename);
			} else if (strcmp(cmd, PRT) == 0) {
				char buf[8];
				length = read(cfp_cmd, buf, 8);
				buf[length] = '\0';
				int portnum = atoi(buf + 1);
				cmd_prt(portnum);
			}
		}
	}
}
void cmd_prt(int portnum) {
	ack_ok();
	struct sockaddr_in s_add_data;
	printf("building data channel via port %d...\n", portnum);
	cfp_data = socket(AF_INET, SOCK_STREAM, 0);
	bzero(&s_add_data, sizeof(struct sockaddr_in));
	s_add_data.sin_family = AF_INET;
	s_add_data.sin_addr.s_addr = inet_addr(client_ip);
	s_add_data.sin_port = htons(portnum);
	printf("s_addr = %#x ,port : %#x\r\n", s_add_data.sin_addr.s_addr,
			s_add_data.sin_port);
	if (-1
			!= connect(cfp_data, (struct sockaddr *) (&s_add_data),
					sizeof(struct sockaddr))) {
		printf("connect data channel success !\r\n");
		return;
	}
}
void cmd_dir() {
	printf("client command:DIR\n");
	system("ls -l > file.list") ;
	cmd_get("file.list");//cmd_dir本身不需要ack_ok，cmd_get里会提供;
}
void cmd_bye() {
/*	printf("client command:BYE\n");
	if (-1 != close(cfp_data)) {
		printf("closed cfp_data\n");
		ack_ok();
		sleep(2); //延时3秒，确保client socket先关
		close(cfp_cmd);
		printf("closed cfp_cmd\n");
	} else {ee
		ack_er();
		printf("close cfp_data error!");
	}*/
//	sleep(1);
	if(cfp_cmd!=-1){
		close(cfp_cmd);
		printf("close command channel!\n");
	}
	if(cfp_data!=-1){
		close(cfp_data);
		printf("close data channel!\n");
	}
}
void cmd_get(char* filename) {
	if(access(filename,R_OK)==-1){
		ack_er();
		return ;
	}
	int fp = open(filename, O_RDONLY);
		ack_ok();
		long filesize = get_file_size(filename);
		char sizestr[16];
		sprintf(sizestr, "%ld", filesize);

		printf("file size:%s\n", sizestr);
		long total_size = strlen(sizestr) + 1 + filesize; //需要发送数据位数，空格，数据
		char buf[total_size];
		strcpy(buf, sizestr);
		buf[strlen(sizestr)] = ' ';
		int length = read(fp, buf+strlen(sizestr)+1, filesize);
		//sprintf(send_str,"%ld %s",filesize,buf);
		close(fp);
		if (length == -1) {
			printf("read file error!\n");
			return;
		} else {
#ifdef TEST
			printf("%s\n",buf);
#endif
			write(cfp_data, buf , total_size);
			return;
		}
	}


void ack_ok() { //命令通道返回OK
#ifdef TEST
	printf("ack_ok\n");
#endif
	send(cfp_cmd, "OK", 2,MSG_WAITALL);
}
void ack_er() { //命令通道返回ER
#ifdef TEST
	printf("ack_er\n");
#endif
	send(cfp_cmd, "ER", 2,MSG_WAITALL);
}
long get_file_size(char* filename) {
	FILE* fp = fopen(filename, "r");
	fseek(fp, 0L, SEEK_END);
	long size = ftell(fp);

	fclose(fp);
	return size;
}
